package com.example.demo.framework.exception;

import com.example.demo.framework.filters.tracer.TraceInfo;
import com.example.demo.framework.utils.TraceUtils;
import com.example.demo.response.ApiResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.Optional;

/**
 * @version v1.0
 * @ClassName: GlobalExceptionResolver
 * @Description:
 * @author: miaoguoxin
 * @date: 2019/9/18 14:19
 */
@ControllerAdvice
@Slf4j
@ConditionalOnProperty(value = "biz.exception-resolve",havingValue = "true",matchIfMissing = true)
public class GlobalExceptionResolver {



    /**
     * @Description: 方法参数异常
     * @Param:
     * @return:
     * @Author: miaoguoxin
     * @Date: 2019/10/27
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseBody
    public ApiResult handelMethodArgException(MethodArgumentNotValidException e) {
        String errMsg = Optional.of(e.getBindingResult()).map(GlobalExceptionResolver::getErrMsg).orElse("");
        return new ApiResult<>(1000, errMsg);
    }



    /**
     * @Description: 处理其他异常
     * @Param:
     * @return:
     * @Author: miaoguoxin
     * @Date: 2019/10/29
     */
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public ApiResult handlerOtherException(Exception e) {
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
        HttpServletResponse response = servletRequestAttributes.getResponse();
        if (e instanceof HttpMediaTypeNotSupportedException){
            if (response != null) {
                response.setStatus(HttpStatus.UNSUPPORTED_MEDIA_TYPE.value());
            }
            return ApiResult.error("不支持的Content-Type");
        }
        if (e instanceof HttpMessageNotReadableException) {
            if (response != null) {
                response.setStatus(HttpStatus.BAD_REQUEST.value());
            }
            return ApiResult.error("参数格式不正确");
        }
        if (e instanceof HttpRequestMethodNotSupportedException) {
            if (response != null) {
                response.setStatus(HttpStatus.METHOD_NOT_ALLOWED.value());
            }
            return ApiResult.error(e.getMessage());
        }
        TraceInfo traceInfo = TraceUtils.get();
        log.info("trace信息:{}",traceInfo);
        log.error("其他异常:{}", e);
        return new ApiResult<>(0);
    }


    private static String getErrMsg(BindingResult result) {
        List<FieldError> fieldErrors = result.getFieldErrors();
        return fieldErrors.stream().findFirst()
                .map(DefaultMessageSourceResolvable::getDefaultMessage).orElse("未知参数错误");
    }


}
